/* UART asynchronous example, that uses separate RX and TX tasks

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <stdio.h>
#include <ctype.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

#include "uart1_cmd.h"
#include "xlx_action.h"
#include "xlx_func.h"
#include "xlx_platform.h"

static const char* TAG = "uart1";

#define _UART_MODE_EVENT_

#if defined(_UART_MODE_)
  int s= 100;
else if defined(_UART_MODE_EVENT_)
  int s= 100;
  . l
else 
 int s= 100;
 p
#endif

#define TXD_PIN (GPIO_NUM_6)
#define RXD_PIN (GPIO_NUM_7)

#define RX_BUF_SIZE (BUF_SIZE)

#define AT_CUSTOM_CMD_MAX   8
char * AT_CUSTOM_CMD[AT_CUSTOM_CMD_MAX] = {
    "AT+XLX=ACTION,",   // 要放前面
    "AT+APP=ACTION,",
    "AT+L342=ACTION,",
    "AT+EWIN=ACTION,",    
    "AT+XLX=",          // 放后面
    "AT+APP=",
    "AT+L342=",
    "AT+EWIN="
};

char uart1_at_out_buffer[AT_CMD_OUT_BUFF_SIZE_MAX];
//char * uart1_at_out_buffer;      // 动态分配

/*
 * 有几种接收串口数据的方式 select/异步/event
 * event方式适合AT命令，采样这个
*/


/*
//----------------------------------串口日志+at指令响应--------------------------------
* 处理串口收到的数据
AT+XLX=action,Version
AT+APP=action,GetBattery
at+L342=action,Version
at+EWIN=action,Version

改IMEI: AT+MTSETID=1,<imei>
*/

/*
* 动态分配内存看看
*/


typedef struct _uart_buff{
    unsigned short len;
    //char * buff;
    char buff[RX_BUF_SIZE];
}uart_buff_t;

static uart_buff_t uart_handle_buff = {0};   // 处理长字符串
static void xlx_uart1_handle(char * buff, uint16_t buf_len)
{
    char *argv[32]; // 32个参数
    int c = 0;
    uint16_t cmd_head_pos;
    char * cmd_buff;
    char * cmd_upcase_buff;

    if(buf_len < 1){
        return;
    }

    if((uart_handle_buff.len + buf_len) > RX_BUF_SIZE){
        TUTU_LOGI(TAG, "sizeof(uart_buff_t)= %d",sizeof(uart_buff_t));
        memset(uart_handle_buff.buff, 0, RX_BUF_SIZE);
        uart_handle_buff.len = 0;
    }

    // 保存数据
    uart_handle_buff.len += buf_len;
    strcat(uart_handle_buff.buff, buff);

    cmd_upcase_buff = (char *)malloc( uart_handle_buff.len);
    memcpy(cmd_upcase_buff, uart_handle_buff.buff, uart_handle_buff.len);     // 用于大写查找字符    
    if(cmd_upcase_buff == NULL){
        return;
    }
    // 判断是否有 换行回车
    cmd_head_pos = search_sub_str_position("\x0d\x0a", (uart_handle_buff.buff));
    if(cmd_head_pos){
        uart_handle_buff.buff[cmd_head_pos-1] = 0x00;
        uart_handle_buff.buff[cmd_head_pos-2] = 0x00;
    }
    else {
        return;
    }
    //TUTU_LOGI(TAG, "buf_len= %d", strlen(buff));
    // xlx_print_hex("buf:", buff, strlen(buff));

#if 0
    // 去掉换行回车
    cmd_head_pos = search_sub_str_position("\r", buff);
    if(cmd_head_pos){
        buff[cmd_head_pos-1] = 0x00;
    }
    cmd_head_pos = search_sub_str_position("\n", buff);
    if(cmd_head_pos){
        buff[cmd_head_pos-1] = 0x00;
    }
#endif
    // TUTU_LOGI(TAG, "buf_len= %d", strlen(buff));
    // xlx_print_hex("buf:", buff, strlen(buff));

    // 兼容 +XLX/+L342/+APP
    // 转换为大写
    //str_to_upper(buff);
    str_to_upper(cmd_upcase_buff);
    for (uint16_t i = 0; i < AT_CUSTOM_CMD_MAX; i++)
    {
        cmd_head_pos = search_sub_str_position(AT_CUSTOM_CMD[i], cmd_upcase_buff);
        if(cmd_head_pos > 0)
        {
            break;
        }
    }
    free(cmd_upcase_buff);

    cmd_buff = uart_handle_buff.buff+cmd_head_pos;       //　去掉前面表示符号
    TUTU_LOGI(TAG, "buff(buf_len= %d): %s", strlen(uart_handle_buff.buff), uart_handle_buff.buff);
    xlx_print_hex("Buf:", uart_handle_buff.buff, strlen(uart_handle_buff.buff));
    c = xlx_split_string(cmd_buff,",",argv,32) - 1;
    if(c > 0){
        memset(uart1_at_out_buffer,0,AT_CMD_OUT_BUFF_SIZE_MAX);           

        TUTU_LOGI(TAG, "params_cnt=%d", c);
        for ( uint16_t i = 0; i < c; i++)
        {
            TUTU_LOGI(TAG, "argv[%d]: %s", i, argv[i]);
        }

        xlx_action_process_at_data(uart1_at_out_buffer,c,argv);
        // 发送
        uart_write_bytes(UART_NUM_1, uart1_at_out_buffer, strlen(uart1_at_out_buffer));
        uart_write_bytes(UART_NUM_1, "\r\n", 2);    
    }    

    // 动态分配的
    memset(uart_handle_buff.buff,0,RX_BUF_SIZE);
    uart_handle_buff.len = 0;
}


#if 1
#define EX_UART_NUM UART_NUM_1
#define PATTERN_CHR_NUM    (3)         /*!< Set the number of consecutive and identical characters received by receiver which defines a UART pattern*/

static QueueHandle_t uart1_queue;

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    char* dtmp = (char*) malloc(RX_BUF_SIZE);
    for (;;) {
        //Waiting for UART event.
        if (xQueueReceive(uart1_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
            bzero(dtmp, RX_BUF_SIZE);
            TUTU_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch (event.type) {
            //Event of UART receving data
            /*We'd better handler data event fast, there would be much more data events than
            other types of events. If we take too much time on data event, the queue might
            be full.*/
            case UART_DATA:
                TUTU_LOGI(TAG, "[UART DATA]: %d", event.size);
                uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
                xlx_uart1_handle(dtmp, event.size);
                // TUTU_LOGI(TAG, "[DATA EVT]:");
                // uart_write_bytes(EX_UART_NUM, (const char*) dtmp, event.size);
                break;
            //Event of HW FIFO overflow detected
            case UART_FIFO_OVF:
                TUTU_LOGI(TAG, "hw fifo overflow");
                // If fifo overflow happened, you should consider adding flow control for your application.
                // The ISR has already reset the rx FIFO,
                // As an example, we directly flush the rx buffer here in order to read more data.
                uart_flush_input(EX_UART_NUM);
                xQueueReset(uart1_queue);
                break;
            //Event of UART ring buffer full
            case UART_BUFFER_FULL:
                TUTU_LOGI(TAG, "ring buffer full");
                // If buffer full happened, you should consider increasing your buffer size
                // As an example, we directly flush the rx buffer here in order to read more data.
                uart_flush_input(EX_UART_NUM);
                xQueueReset(uart1_queue);
                break;
            //Event of UART RX break detected
            case UART_BREAK:
                TUTU_LOGI(TAG, "uart rx break");
                break;
            //Event of UART parity check error
            case UART_PARITY_ERR:
                TUTU_LOGI(TAG, "uart parity error");
                break;
            //Event of UART frame error
            case UART_FRAME_ERR:
                TUTU_LOGI(TAG, "uart frame error");
                break;
            //UART_PATTERN_DET
            case UART_PATTERN_DET:
                uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                int pos = uart_pattern_pop_pos(EX_UART_NUM);
                TUTU_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                if (pos == -1) {
                    // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                    // record the position. We should set a larger queue size.
                    // As an example, we directly flush the rx buffer here.
                    uart_flush_input(EX_UART_NUM);
                } else {
                    uart_read_bytes(EX_UART_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
                    uint8_t pat[PATTERN_CHR_NUM + 1];
                    memset(pat, 0, sizeof(pat));
                    uart_read_bytes(EX_UART_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
                    TUTU_LOGI(TAG, "read data: %s", dtmp);
                    TUTU_LOGI(TAG, "read pat : %s", pat);
                }
                break;
            //Others
            default:
                TUTU_LOGI(TAG, "uart event type: %d", event.type);
                break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

static void uart1_init(void)
{
    esp_log_level_set(TAG, ESP_LOG_INFO);

#if 0
    // 动态分配
    uart_handle_buff.buff = (char *)malloc(RX_BUF_SIZE);
    if(NULL == uart_handle_buff.buff){
        TUTU_LOGE(TAG, "malloc uart_buff ERROR!");
        return;
    }
    else {
        TUTU_LOGI(TAG, "malloc uart_buff OK(%p)!", uart_handle_buff.buff);
        memset(uart_handle_buff.buff, 0, RX_BUF_SIZE);
    }

    // 动态分配
    uart1_at_out_buffer = (char *)malloc(AT_CMD_OUT_BUFF_SIZE_MAX);
    if(NULL == uart1_at_out_buffer){
        TUTU_LOGE(TAG, "malloc uart_buff ERROR!");
        return;
    }
    else {
        TUTU_LOGI(TAG, "malloc uart1_at_out_buffer OK(%p)!", uart1_at_out_buffer);
        memset(uart1_at_out_buffer, 0, AT_CMD_OUT_BUFF_SIZE_MAX);
    }
#endif    

    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    //Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 30, &uart1_queue, 0);
    uart_param_config(EX_UART_NUM, &uart_config);

    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(EX_UART_NUM, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 119, 0, 0);
    //Reset the pattern queue length to record at most 20 pattern positions.
    uart_pattern_queue_reset(EX_UART_NUM, 30);
}

void uart1_task_init(void)
{
    uart1_init();
    //Create a task to handler UART event from ISR
    int ret = xTaskCreate(uart_event_task, "Uart1", 512*12, NULL, 12, NULL);
    if (ret != pdTRUE) {
        TUTU_LOGE(TAG, "%s(ret=%d)\r\n", "Uart1 task create fail!", ret);        

    }
    else {
         TUTU_LOGI(TAG, "%s(ret=%d)\r\n", "Uart1 task create OK", ret);
    }    
}

#else
// 使用异步接收处理方式
static void uart1_init(void)
{
    const uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    // We won't use a buffer for sending data.
    uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
    uart_param_config(UART_NUM_1, &uart_config);
    uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

static void rx_task(void *arg)
{
    static const char *RX_TASK_TAG = "RX_TASK";
    esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
    char* data = (char*) malloc(RX_BUF_SIZE + 1);
    while (1) {
        const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX_BUF_SIZE, 190 / portTICK_PERIOD_MS);
        if (rxBytes > 0) {
            data[rxBytes] = 0;
            xlx_uart1_handle(data, rxBytes);
        }
    }
    free(data);
}

void uart1_task_init(void)
{
    uart1_init();
    int ret = xTaskCreate(rx_task, "uart1_rx_task", 1024 * 2, NULL, configMAX_PRIORITIES - 1, NULL);
    if (ret != pdTRUE) {
        TUTU_LOGE(TAG, "%s(ret=%d)\r\n", "Uart1 task create fail!", ret);        

    }
    else {
         TUTU_LOGI(TAG, "%s(ret=%d)\r\n", "Uart1 task create OK", ret);
    }        
    
}
#endif

